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

# Incorporar y Verificar una Empresa

> Ejecuta el flujo feliz de empresa de extremo a extremo: configura una aplicación restringida a cuentas de empresa, envía a un propietario por OAuth, registra la entidad legal y sigue el KYB hasta una cuenta de empresa aprobada.

Esta guía rápida es [Incorporar y Conectar a un Cliente](/quickstart/onboard-customers) para empresas. Configurarás una aplicación que solo puede terminar en una cuenta de empresa, guiarás a un propietario por la concesión OAuth, registrarás su entidad legal y su lista de beneficiarios finales, seguirás el caso de KYB hasta una decisión y probarás la conexión emitiendo una tarjeta en la cuenta de empresa.

La persona que tienes enfrente siempre es un individuo primero. Inicia sesión como ella misma, verifica su identidad como ella misma y *después* registra una empresa. Todo lo que sigue respeta ese orden.

<Info>
  **Requisitos previos**

  * Una **cuenta de Fluz con una aplicación en staging** — consulta [Prepara tus cuentas](/get-started/prepare-accounts) y [Credenciales de API](/get-started/api-credentials).
  * Un `client_id`, un `client_secret` y un `redirect_uri` registrado — consulta [Configurar aplicación OAuth](/create-an-o-auth-app).
  * Las solicitudes van al **sandbox** — sin dinero real, sin PII real. Consulta [Entorno de Staging vs. Producción](/concepts/environments).
</Info>

## El flujo completo

<Steps>
  <Step title="Configura la aplicación para empresas" icon="sliders">
    En la pestaña **Permissions** de tu app viven dos listas de permisos, y se editan de forma independiente.

    | Lista                    | Qué poner en ella                                                                                                                                                                       |
    | :----------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | **Permissions**          | Lo que tu app puede hacer sobre una cuenta **personal**. Incluye el permiso de **registrar una empresa** — lo otorga la cuenta personal, así que pertenece aquí y en ningún otro lugar. |
    | **Business permissions** | Lo que tu app puede hacer sobre una cuenta **de empresa** una vez que exista.                                                                                                           |

    Una lista **Business permissions** no vacía es lo que habilita tu app para empresas. Déjala vacía y a los usuarios nunca se les ofrecerá la opción de solicitar una cuenta de empresa, sin importar qué más configures.

    Ya que estás en el editor de la app, registra tu `redirect_uri` en la pestaña **OAuth** y agrega una URL de webhook suscrita a **actualización de estado de KYB** — así te enterarás de que la revisión terminó sin hacer polling.

    <Warning>
      La pantalla de consentimiento se construye a partir de estas listas, no de tu URL de authorize. Un permiso que no selecciones aquí nunca se le ofrece al usuario y nunca puede aparecer en un token. Detalle completo: [Cuentas de empresa en OAuth](/business-accounts-in-o-auth).
    </Warning>
  </Step>

  <Step title="Pide a Fluz que restrinja la app a cuentas de empresa" icon="building-lock">
    Fluz puede configurar tu aplicación para que el flujo nunca se resuelva en una cuenta personal. Con eso en marcha, un usuario que no tiene cuenta de empresa se salta por completo el selector de cuenta y entra directo al registro de empresa.

    <Warning>
      **Esto no es autogestionable.** Contacta a tu gerente de cuenta de Fluz para que aplique la restricción a tu aplicación. Hasta entonces, a los usuarios sin cuenta de empresa se les ofrece su cuenta personal junto con la opción de solicitar una de empresa — y algunos elegirán la personal.
    </Warning>

    Omite este paso si tu app atiende legítimamente tanto a consumidores como a empresas. Pedirla es afirmar que una concesión sobre cuenta personal siempre es un error en tu caso.
  </Step>

  <Step title="Envía al propietario por la concesión OAuth" icon="plug">
    Construye la URL de authorize:

    ```text Authorization URL theme={null}
        https://uni.staging.fluzapp.com/authorize
          ?response_type=code
          &client_id=<YOUR_OAUTH_CLIENT_ID>
          &redirect_uri=<YOUR_REGISTERED_REDIRECT_URI>
          &state=<UNGUESSABLE_VALUE_YOU_STORED>
          &external_id=<YOUR_ID_FOR_THIS_ACCOUNT>
    ```

    Con la app restringida a cuentas de empresa, un usuario que entra por primera vez ve: inicio de sesión y 2FA, y luego una pantalla de consentimiento con **dos grupos** — los permisos de consumidor que otorga ahora, y los permisos de empresa que se pre-aprueban para la empresa que está por crear. La lista es de solo lectura; acepta todo o no termina.

    Se le redirige de vuelta a tu `redirect_uri` con `?code=...&state=...`. Valida el `state` y luego captura el `code` de un solo uso del lado del servidor.

    <Tip>
      Dale a la **empresa** su propio `external_id`, derivado de tu propio registro de empresa — no del usuario propietario. Un ID externo se vincula a una sola cuenta de Fluz en su primer uso, así que un ID que gastes en la cuenta personal de alguien no podrá reutilizarse para su empresa.
    </Tip>

    Referencia completa de parámetros: [Flujo de concesión OAuth orientado al cliente](/client-facing-o-auth-grant-flow).
  </Step>

  <Step title="Intercambia el código por el token del solicitante" icon="key">
    El mismo intercambio que en cualquier otra concesión — autenticación básica con base64 de `client_id:client_secret`:

    ```bash Exchange (cURL) theme={null}
        curl -X GET "https://uni.staging.fluzapp.com/token/exchange?code=<AUTH_CODE>&redirect_uri=<YOUR_REGISTERED_REDIRECT_URI>" \
          -H "Authorization: Basic <base64 of CLIENT_ID:CLIENT_SECRET>"
    ```

    El `redirect_uri` debe coincidir byte a byte con el que usaste en `/authorize`.

    <Note>
      La empresa todavía no existe, así que este token pertenece a la cuenta **personal** del solicitante — eso es correcto, y es el token que `registerBusiness` requiere. Lee la cuenta de la respuesta del intercambio y persístela, en lugar de inferirla de tus propios registros de quién inició el flujo.
    </Note>
  </Step>

  <Step title="Verifica la identidad del solicitante (KYC)" icon="id-card">
    KYB verifica la empresa y a los *demás* propietarios. No verifica al solicitante, así que el solicitante tiene que estar verificado antes de que registres nada — de lo contrario el registro falla con `ARG-0001`.

    Llama a `verifyUserInformation` con el token del solicitante. En staging esta identidad de prueba siempre devuelve `APPROVED`:

    <CodeGroup>
      ```graphql Mutation theme={null}
          mutation VerifyUserInformation(
            $firstName: String!
            $lastName: String!
            $streetLine1: String!
            $city: String!
            $state: String!
            $postalCode: String!
            $country: String!
            $dateOfBirth: String!
            $ssnLast4: String!
          ) {
            verifyUserInformation(
              firstName: $firstName
              lastName: $lastName
              streetLine1: $streetLine1
              city: $city
              state: $state
              postalCode: $postalCode
              country: $country
              dateOfBirth: $dateOfBirth
              ssnLast4: $ssnLast4
            ) {
              status
              message
            }
          }
      ```

      ```json Variables (approved test identity) theme={null}
          {
            "firstName": "John",
            "lastName": "Smith",
            "streetLine1": "222333 Peachtree Place",
            "city": "Atlanta",
            "state": "GA",
            "postalCode": "30318",
            "country": "United States",
            "dateOfBirth": "02/28/1975",
            "ssnLast4": "3333"
          }
      ```
    </CodeGroup>

    Qué comprobación necesita el solicitante depende del valor de `isUsPerson` que enviarás para él en el siguiente paso: `true` requiere una verificación por SSN (CIP) exitosa ya registrada, `false` requiere una verificación por documentos exitosa. Consulta [Verificación KYC de usuarios](/user-kyc-verification) y [Pruebas de flujos KYC](/test-kyc-flows).

    <Warning>
      Un usuario puede enviarse como máximo **3 veces** antes de devolver `ERROR`. No gastes intentos en el usuario que estás por convertir en solicitante.
    </Warning>
  </Step>

  <Step title="Registra la empresa" icon="building">
    Primero resuelve la categoría bajo la que opera la entidad — nunca fijes estos UUID en el código:

    ```graphql theme={null}
        query {
          getBusinessCategories {
            id
            name
            subCategories { id name }
          }
        }
    ```

    Luego envía la entidad y la lista completa de propietarios en una sola llamada, todavía con el token de la cuenta **personal** del solicitante:

    <CodeGroup>
      ```graphql Mutation theme={null}
          mutation RegisterBusiness($input: RegisterBusinessInput!) {
            registerBusiness(input: $input) {
              accountId
              kybStatus
              success
              error { code message }
            }
          }
      ```

      ```json Variables theme={null}
          {
            "input": {
              "businessName": "Acme Corporation",
              "dbaName": "Acme Co",
              "businessStructure": "LLC",
              "businessLegalAddress": {
                "streetAddressLine1": "123 Main Street",
                "city": "San Francisco",
                "state": "California",
                "postalCode": "94102",
                "country": "United States"
              },
              "stateOfIncorporation": "California",
              "taxId": "12-3456789",
              "businessCategoryId": "<FROM_getBusinessCategories>",
              "businessSubCategoryId": "<FROM_getBusinessCategories>",
              "natureOfBusiness": "E-commerce retail",
              "businessAccountUsage": ["CORPORATE_SPENDING_ADMIN"],
              "externalReferenceId": "your-business-id-123",
              "confirm": {
                "allOwnersWith25PercentageOwnershipListed": true,
                "noOwnersMoreThan25Percentage": false
              },
              "owners": [
                {
                  "firstName": "John",
                  "lastName": "Smith",
                  "emailAddress": "john@example.com",
                  "phoneNumber": "+14155551234",
                  "title": "Chief Executive Officer",
                  "ownershipPercentage": 100,
                  "isControlPerson": true,
                  "isInvited": false,
                  "isUsPerson": true
                }
              ]
            }
          }
      ```
    </CodeGroup>

    Una respuesta exitosa devuelve un `accountId` y un `kybStatus` de `SUBMITTED`. Guarda el `accountId` de inmediato — es tu único identificador de la solicitud.

    Tres cosas que hacen fallar la mayoría de los primeros intentos:

    * **`isUsPerson` es obligatorio en cada propietario**, incluidos el solicitante y los propietarios invitados. Es la causa más común de una lista rechazada.
    * **Exactamente un propietario debe ser el solicitante** — identificado por correo o teléfono contra el usuario del token — y exactamente uno debe ser la persona de control.
    * **La dirección legal se valida contra un proveedor de validación de direcciones.** Las calles inventadas fallan con `BS-0002`; usa [Direcciones de prueba](/test-addresses).

    <Warning>
      Los errores vuelven **dentro del payload de la respuesta**, no como errores de GraphQL — ramifica según `success` y el objeto `error`. Referencia completa de parámetros y errores: [Registro de empresas](/business-registration).
    </Warning>
  </Step>

  <Step title="Consigue que los demás propietarios se verifiquen, y luego espera" icon="users">
    `SUBMITTED` significa que el payload pasó la validación y se abrió un caso. No significa aprobado.

    Genera un token de **cuenta de empresa** — `generateUserAccessToken` con el `userId` del solicitante y el nuevo `accountId` de la empresa — y lee la lista de propietarios:

    ```graphql theme={null}
        query GetBusiness {
          getBusiness {
            accountId
            kybStatus
            owners { id name verificationType status }
          }
        }
    ```

    Los propietarios en la ruta documental reciben un enlace de [requestOwnerDocumentVerificationLink](/owner-verification-link); a los propietarios que marcaste con `isInvited: true` los contacta Fluz por correo y se verifican solos. Sigue consultando hasta que `kybStatus` sea final **y** cada propietario reporte `READY`.

    El estado pasa de `PENDING` a `APPROVED` o `DECLINED`, normalmente en uno o dos días hábiles. Toma la decisión del webhook de **actualización de estado de KYB** que configuraste en el paso 1 y usa `getBusiness` para reconciliar — cada hora, no en cada carga de página.

    <Note>
      Muéstrale al usuario un estado honesto de "en revisión". No lo dejes en un panel de empresa que todavía no puede transaccionar, y no reintentes automáticamente tras un rechazo — un segundo envío se bloquea con `BS-0007`. Ciclo de vida completo: [Registro de empresas](/business-registration).
    </Note>
  </Step>

  <Step title="Opera sobre la cuenta de empresa — demuéstralo" icon="credit-card">
    Una vez que `kybStatus` sea `APPROVED`, ejecuta cualquier operación de Fluz con el token de la **cuenta de empresa** y se ejecutará contra la empresa. No hay una API de empresa aparte.

    ```graphql theme={null}
        mutation {
          createVirtualCard(
            input: {
              idempotencyKey: "9f2c4d61-77aa-4b0e-8f2a-1c9d3e5b7a04"
              offerId: "ed669305-5e43-40a0-9a25-7a15ed174628"
              spendLimit: 250.00
              lockCardNextUse: true
              cardNickname: "First card on a verified business"
            }
          ) {
            virtualCardId
            virtualCardLast4
            status
          }
        }
    ```

    Que vuelva una tarjeta `ACTIVE` significa que el ciclo se cerró: configurada → autorizada → verificada → registrada → aprobada → operando.
  </Step>
</Steps>

## Listo 🎉

Llevaste una empresa desde una aplicación vacía hasta una cuenta verificada que puede gastar. Desde aquí:

<CardGroup cols={2}>
  <Card title="Cuentas de empresa en OAuth" icon="building-lock" href="/business-accounts-in-o-auth">
    Las dos listas de permisos, el selector de cuenta y a qué cuenta resuelve un código.
  </Card>

  <Card title="Registro de empresas" icon="clipboard-check" href="/business-registration">
    Requisitos previos, el ciclo de vida del estado de KYB y cómo seguir un caso hasta la decisión.
  </Card>

  <Card title="Enviar documentos comerciales" icon="file-arrow-up" href="/submit-business-documents">
    Cargas de firmante autorizado y respuesta a solicitudes de documentación.
  </Card>

  <Card title="Incorporar y conectar a un cliente" icon="user-plus" href="/quickstart/onboard-customers">
    El mismo recorrido para individuos.
  </Card>
</CardGroup>

<Note>
  **¿Quieres saber más?** Escríbenos a [support@fluz.app](mailto:support@fluz.app) para hablar con nuestros expertos o solicitar una demo.
</Note>
