Skip to content

Companies and verification

View as Markdown

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 one of its users.

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

A user logged in with canManageCompany: false can read the company. The requests on this page that change it fail with user_cannot_manage_company.

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.

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.

When the status changes, Beauty Router sends a company.verification_updated webhook.

Call showVerification(element) from the JavaScript library. 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 returns the company’s verificationStatus, so you know what to show the user.

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.

The payment card is still entered in Beauty Router’s interface. See Payment card.

Show “Powered by Beauty Router” and a link to Beauty Router’s terms on these screens. See Beauty Router mark.

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

Terminal window
curl https://api.beautyrouter.com/v1/company \
-H "Authorization: Bearer $USER_TOKEN"
{
"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.

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.
Terminal window
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.

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.

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:

{
"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.

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.

A company needs at least one license. See 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.
Terminal window
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:

{
"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. DELETE /v1/company/licenses/{licenseId} deletes a license.

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.

Terminal window
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:

{
"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. DELETE /v1/company/exemption-certificates/{certificateId} deletes a certificate.

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

Terminal window
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:

{
"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.

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:

{
"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. pendingChanges is null when no change waits for review.

These endpoints save the selection described in Services.

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

Terminal window
curl https://api.beautyrouter.com/v1/services \
-H "Authorization: Bearer $USER_TOKEN"
{
"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:

Terminal window
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:

{
"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.

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.

Terminal window
curl https://api.beautyrouter.com/v1/company/payment-cards \
-H "Authorization: Bearer $USER_TOKEN"
{
"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.

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.