# Companies and verification

Beauty Router reviews each company before it can order. A company is one salon location or one licensed professional. It
is created the first time your server [logs in](/authentication/) one of its users.

You can collect the company's details in two ways:

- **[Use Beauty Router's verification page](#use-beauty-routers-verification-page).** This is the easiest path.
- **[Build your own screens](#build-your-own-screens).** Send the details and documents over the API, then submit the
  company for review.

A user logged in with [`canManageCompany: false`](/authentication/#users-who-cannot-change-company-settings) can read the
company. The requests on this page that change it fail with `user_cannot_manage_company`.

## Business types

| Type           | Who it is                           |
| -------------- | ----------------------------------- |
| `salon`        | A salon or spa                      |
| `professional` | An individual licensed professional |
| `store`        | A beauty supply store               |

`businessType` is `null` until the company picks a type.

Beauty Router does not support beauty supply stores yet, so verification for a `store` always fails.

## Verification statuses

| Status         | Meaning                                                                               |
| -------------- | ------------------------------------------------------------------------------------- |
| `unverified`   | The company was not submitted for review yet.                                         |
| `in_review`    | Beauty Router is reviewing the company.                                               |
| `prequalified` | The initial check passed, and the detailed verification is still pending.             |
| `verified`     | The company passed the review.                                                        |
| `declined`     | The company did not pass the review.                                                  |

A `prequalified` company can order, and its orders wait until the detailed verification ends. No charge happens until
then. When a company is declined, its orders close.

Wholesale prices and ordering open only once the company is `prequalified` or `verified`. That holds in Beauty Router's
interface and in the API, where any other company gets `company_not_verified`. See [Create orders](/create-orders/).

When the status changes, Beauty Router sends a `company.verification_updated` [webhook](/webhooks/).

## Use Beauty Router's verification page

Call `showVerification(element)` from the [JavaScript library](/embedded-marketplace/). The page collects the company
details, the documents, and the payment card, and it submits the company for review. You do not need the endpoints in
the next section on this path.

Each [login](/authentication/) returns the company's `verificationStatus`, so you know what to show the user.

## Build your own screens

Use these endpoints to collect the details on your own screens. You can update company details one by one, and upload
documents one by one. Each step is saved in Beauty Router, so intermediate steps are kept. When everything is ready,
[submit the company for review](#submit-for-review).

The payment card is still entered in Beauty Router's interface. See [Payment card](#payment-card).

Show "Powered by Beauty Router" and a link to [Beauty Router's terms](https://beautyrouter.com/terms/) on these screens. See
[Beauty Router mark](/embedded-marketplace/#beauty-router-mark).

### Read the company

`GET /v1/company` returns the company of the logged-in user.

```bash
curl https://api.beautyrouter.com/v1/company \
  -H "Authorization: Bearer $USER_TOKEN"
```

```json
{
  "id": "loc-7Hk2pQx9Lm",
  "businessType": "salon",
  "displayName": "Golden Hour Hair Studio",
  "legalName": "Golden Hour Salon LLC",
  "ein": "847102938",
  "deliveryAddress": {
    "line1": "1450 Larimer St",
    "line2": "Suite 200",
    "city": "Denver",
    "state": "CO",
    "postalCode": "80202",
    "country": "US",
    "phone": "+13035550142"
  },
  "verificationStatus": "verified",
  "buyingSuspended": false,
  "pendingChanges": null
}
```

Fields the company has not filled in yet are `null`.

`buyingSuspended` is `true` when Beauty Router suspended the company's buying. The company can still read its data and
manage its orders, but it cannot place a new order.

### Update the company

`PUT /v1/company` accepts a partial update. Send only the fields you change, and fields you leave out stay as they are.

| Field             | Description                                                     |
| ----------------- | --------------------------------------------------------------- |
| `businessType`    | `salon`, `professional`, or `store`.                            |
| `displayName`     | The name the company goes by.                                   |
| `legalName`       | The registered legal name. Not used for `professional`.         |
| `ein`             | The Employer Identification Number, 9 digits. Not used for `professional`. |
| `deliveryAddress` | The default delivery address. See the fields below.             |

| `deliveryAddress` field | Description                         |
| ----------------------- | ----------------------------------- |
| `line1`                 | Street address.                     |
| `line2`                 | Suite, unit, or floor. Optional.    |
| `city`                  | City.                               |
| `state`                 | Two-letter US state code, such as `CO`. |
| `postalCode`            | ZIP code.                           |
| `country`               | Always `US`.                        |
| `phone`                 | Phone number for the delivery. Required on the company. |

```bash
curl -X PUT https://api.beautyrouter.com/v1/company \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "businessType": "salon",
    "displayName": "Golden Hour Hair Studio",
    "legalName": "Golden Hour Salon LLC",
    "ein": "847102938"
  }'
```

The response is the company.

What happens to a change depends on the company's status:

- **`unverified` or `declined`.** The change saves and shows directly in `GET /v1/company`.
- **`in_review`, `prequalified`, or `verified`.** A change to `legalName`, `ein`, `displayName`, or `businessType` goes to
  `pendingChanges` until the review. See [Changes after verification](#changes-after-verification).

A company can change its delivery address at any time, in any status. It needs a license in that state only to order:
without one, the order fails with `address_state_without_license` in its [problems](/create-orders/#problems).

The address still saves when the company has no license in that state, and the response has a `warnings` list. It is the
same check as at order time, so an order to that address fails until the company has the license:

```json
{
  "id": "loc-7Hk2pQx9Lm",
  "verificationStatus": "verified",
  "warnings": ["address_state_without_license"]
}
```

The example shows only some of the fields. A warning comes only with the call that saved that address.

A `prequalified` company's license counts as soon as it is uploaded. A `verified` company's license must be reviewed
before an order can go to that state, and uploading the license creates the review task.

### Documents

Send each document in its own request. The request body is the file itself, `Content-Type` is the file's type, such as
`application/pdf`, and `fileName` is a query parameter. The file is a PDF, PNG, JPEG, WebP, GIF, TIFF, HEIC, HEIF, or AVIF
file, up to 30 MB. A larger file fails with `file_too_large`, and another file type fails with
`file_type_not_supported`.

Beauty Router reads the details from the document, so you send only the file. Until it has processed the document,
fields such as `number`, `state`, and `expirationDate` are `null` in reads. `processingStatus` says where that stands:

| Status    | Meaning                                                                |
| --------- | ---------------------------------------------------------------------- |
| `pending` | Beauty Router is reading the document.                                 |
| `done`    | Beauty Router has read the document.                                   |
| `failed`  | Beauty Router could not read the file. Ask the user for a better file. |

To correct a document, delete it and upload it again. There is no update. The same file twice for one company fails with
`document_already_uploaded`.

A document that Beauty Router reviewed can be deleted only while the company is `unverified` or `declined`. Otherwise the
request fails with `document_locked`.

#### Licenses

A company needs at least one license. See [Submit for review](#submit-for-review) for which kind.

`POST /v1/company/licenses` takes these query parameters:

| Field      | Description                                              |
| ---------- | -------------------------------------------------------- |
| `type`     | `business` or `professional`.                            |
| `fileName` | The name of the file, such as `cosmetology-license.pdf`. |

```bash
curl -X POST "https://api.beautyrouter.com/v1/company/licenses?type=professional&fileName=cosmetology-license.pdf" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "Content-Type: application/pdf" \
  --data-binary @cosmetology-license.pdf
```

The response is the new license. Beauty Router has not processed it yet:

```json
{
  "id": "lic-5Bn7vCx1Qe",
  "type": "professional",
  "number": null,
  "state": null,
  "expirationDate": null,
  "firstName": null,
  "lastName": null,
  "processingStatus": "pending"
}
```

`GET /v1/company/licenses` lists the company's licenses, with [paging](/conventions/#paging).
`DELETE /v1/company/licenses/{licenseId}` deletes a license.

#### Exemption certificates

Exemption certificates are optional. Once Beauty Router reviewed a certificate, orders delivered in its state have no
sales tax.

`POST /v1/company/exemption-certificates` takes one query parameter, `fileName`, such as `resale-certificate.pdf`.

```bash
curl -X POST "https://api.beautyrouter.com/v1/company/exemption-certificates?fileName=resale-certificate.pdf" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "Content-Type: application/pdf" \
  --data-binary @resale-certificate.pdf
```

The response is the new certificate. Beauty Router has not processed it yet:

```json
{
  "id": "exc-2Qw7eRt5Yu",
  "state": null,
  "number": null,
  "startDate": null,
  "expirationDate": null,
  "processingStatus": "pending"
}
```

`GET /v1/company/exemption-certificates` lists the company's certificates, with [paging](/conventions/#paging).
`DELETE /v1/company/exemption-certificates/{certificateId}` deletes a certificate.

### Submit for review

`POST /v1/company/verification` submits the company for review. The response is the company, with `verificationStatus` set
to `in_review`.

Beauty Router runs the initial check once it has processed the documents. When the check passes, the status becomes
`prequalified`, and a `company.verification_updated` [webhook](/webhooks/) follows.

```bash
curl -X POST https://api.beautyrouter.com/v1/company/verification \
  -H "Authorization: Bearer $USER_TOKEN"
```

The data a company needs depends on its `businessType`, so set that first:

| Data                   | `salon` or `store`                            | `professional`                    |
| ---------------------- | --------------------------------------------- | --------------------------------- |
| `displayName`          | Required                                      | Required                          |
| `legalName`            | Required                                      | Not used                          |
| `ein`                  | Required                                      | Not used                          |
| `deliveryAddress`      | Required                                      | Required                          |
| Licenses               | At least one business or professional license | At least one professional license |
| Exemption certificates | Optional                                      | Optional                          |

When data is missing, the request fails with `verification_data_missing`, and `missing` lists what to add:

```json
{
  "error": {
    "code": "verification_data_missing",
    "message": "The company needs more data before review.",
    "missing": ["ein", "licenses"]
  }
}
```

A repeated submit, or a submit on a `verified` company, changes nothing.

### Changes after verification

When an `in_review`, `prequalified`, or `verified` company changes `legalName`, `ein`, `displayName`, or `businessType`,
the change goes to review. The status stays the same while Beauty Router reviews it.

During that review, `GET /v1/company` returns the current values, plus the new values in `pendingChanges`:

```json
{
  "id": "loc-7Hk2pQx9Lm",
  "businessType": "salon",
  "displayName": "Golden Hour Hair Studio",
  "legalName": "Golden Hour Salon LLC",
  "ein": "847102938",
  "deliveryAddress": {
    "line1": "1450 Larimer St",
    "line2": "Suite 200",
    "city": "Denver",
    "state": "CO",
    "postalCode": "80202",
    "country": "US",
    "phone": "+13035550142"
  },
  "verificationStatus": "verified",
  "buyingSuspended": false,
  "pendingChanges": {
    "displayName": "Golden Hour Salon and Spa"
  }
}
```

When Beauty Router approves or declines the change, it sends a `company.verification_updated` [webhook](/webhooks/).
`pendingChanges` is `null` when no change waits for review.

### Service endpoints

These endpoints save the selection described in [Services](#services).

`GET /v1/services` lists the services a company can select. It has no paging:

```bash
curl https://api.beautyrouter.com/v1/services \
  -H "Authorization: Bearer $USER_TOKEN"
```

```json
{
  "data": [
    { "id": "svc-2Hk8mNq4Lp", "name": "Hair Color" },
    { "id": "svc-7Tz3bVw9Rc", "name": "Keratin Treatments" }
  ]
}
```

`GET /v1/company/services` returns the company's selection. `PUT /v1/company/services` replaces it. Both have the same
format:

```bash
curl -X PUT https://api.beautyrouter.com/v1/company/services \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "serviceIds": ["svc-2Hk8mNq4Lp", "svc-7Tz3bVw9Rc"] }'
```

`GET /v1/user/services` returns the logged-in user's selection:

```json
{
  "serviceIds": ["svc-2Hk8mNq4Lp", "svc-7Tz3bVw9Rc"],
  "source": "company"
}
```

`source` is `company` when the user follows the company, or `user` when they have their own selection.

`PUT /v1/user/services` takes `serviceIds` and sets the user's own selection, which stays until they remove it. It returns
the same format. An empty list means the user has their own empty selection, so the marketplace shows them all products.
`DELETE /v1/user/services` removes the user's selection, so they follow the company again. The response is `204` with no
body.

Any logged-in user of the company can change the company's selection and their own, including a user with
`canManageCompany: false`. A user who has their own selection keeps it when the company's selection changes.

## Payment card

A company needs a payment card before its first order. The card is entered only in Beauty Router's interface: on the
verification page that `showVerification(element)` shows, or in the small card list that `showPaymentCards(element)`
shows. The API never takes card details. Only cards issued in the US are accepted.

`GET /v1/company/payment-cards` lists the company's cards. Any logged-in user of the company can read it. It has no
paging.

```bash
curl https://api.beautyrouter.com/v1/company/payment-cards \
  -H "Authorization: Bearer $USER_TOKEN"
```

```json
{
  "data": [
    {
      "id": "card-6Mn3bVc8Xz",
      "brand": "visa",
      "last4": "1881",
      "expMonth": 9,
      "expYear": 2028,
      "isDefault": true,
      "usable": true
    }
  ]
}
```

| Field       | Description                                                                      |
| ----------- | -------------------------------------------------------------------------------- |
| `id`        | The card ID, such as `card-6Mn3bVc8Xz`.                                          |
| `brand`     | The card brand, such as `visa` or `mastercard`.                                  |
| `last4`     | The last four digits.                                                            |
| `expMonth`  | The month the card expires, from 1 to 12.                                        |
| `expYear`   | The year the card expires.                                                       |
| `isDefault` | Whether this is the default card for orders.                                     |
| `usable`    | Whether the card can pay. It is `false` when the card expired or was disabled.   |

## Services

A company can select the services it offers, such as hair color or keratin treatments. Beauty Router uses the selection
to personalize the marketplace. It is optional and has no effect on verification.

Services have two levels: the salon location and the user. A user either uses the company's selection or overrides it
with their own. The marketplace personalizes by the user's own selection if they have one, and otherwise by the company's.
With neither, it shows all products.

You can collect the selection in two ways, and both let you choose the level:

- **Show Beauty Router's form.** Call `showServiceSelector(element, { level })`, where `level` is `"company"`, the default,
  or `"user"`. The user selects services there, and can propose a new one.
- **Use the API.** Show the services in your own form, then save the selection. See
  [Service endpoints](#service-endpoints).