# Hallazgos del diagnóstico

Qué significa cada hallazgo del diagnóstico y cada primer paso del recorrido, quién lo arregla y cómo.

Cada hallazgo del diagnóstico (`findings`) tiene aquí su apartado, y su `docsUrl` lleva directo a él. Al final están los primeros pasos del recorrido (`journey`), que se marcan solos. Si empiezas de cero, ve antes a [Probar tu integración](https://os.utilia.ai/docs/developers/getting-started/testing-quickstart); cada ruta del diagnóstico, con sus campos, está en [Rutas del diagnóstico](https://os.utilia.ai/docs/developers/getting-started/diagnostics).

## Cómo se lee un hallazgo

El título de cada apartado es el ancla de su `docsUrl`: el código en minúsculas y con guiones (`SCOPE_MODULE_NOT_IN_PLAN` es `#scope-module-not-in-plan`). Debajo, una línea con el nombre del hallazgo (su `title`), el código, la gravedad y quién lo arregla.

- **Gravedad** (`severity`): `blocking` (sin esto falla lo que intentas), `warning` (funciona, pero hay que revisar algo), `optional` o `info`.
- **Quién lo arregla** (`fixedBy`): tú (`developer`); la organización (`organization`), es decir, un administrador, y no se rodea desde el código; o nosotros (`utilia`).

## Aplicación y credencial

### `app-disabled`

**La aplicación está desactivada** · `APP_DISABLED` · Bloquea · Lo arregla la organización

Todas sus llamadas se rechazan con `APP_DISABLED`. Pide a un administrador de tu organización que la active en la ficha de la aplicación. Solo se ve en la pestaña **Pruebas** del panel y por MCP: con la clave, también el diagnóstico responde [`403 APP_DISABLED`](https://os.utilia.ai/docs/developers/getting-started/errors-and-retries#app_disabled).

### `tenant-suspended`

**La organización está suspendida** · `TENANT_SUSPENDED` · Aviso, o bloquea si se rechazan escrituras · Lo arregla la organización

Las consultas siguen funcionando, pero toda llamada que crea o cambia datos se rechaza con `TENANT_SUSPENDED`. Es un aviso mientras tu aplicación solo consulta; pasa a bloqueo, y la salud a **No funciona**, cuando se están rechazando escrituras suyas. Pide a un administrador que revise la suscripción. Con una clave publicada en una web, el hallazgo conserva el código y dice solo «La organización no está activa».

### `tenant-cancelled`

**La organización está dada de baja** · `TENANT_CANCELLED` · Aviso, o bloquea si se rechazan escrituras · Lo arregla la organización

Como en [`tenant-suspended`](#tenant-suspended): las consultas siguen funcionando, las escrituras se rechazan con `TENANT_CANCELLED` y bloquea solo cuando se rechazan escrituras de tu aplicación. Pide a un administrador que revise la suscripción. Con una clave publicada en una web, el texto es el mismo neutro.

### `responsible-missing`

**La aplicación no tiene persona responsable** · `RESPONSIBLE_MISSING` · Bloquea · Lo arregla la organización

Sin una persona responsable activa, todas sus llamadas se rechazan con `APP_RESPONSIBLE_INACTIVE`. Pide a un administrador que nombre una en la ficha de la aplicación. Solo se ve en la pestaña **Pruebas** del panel y por MCP: con la clave, también el diagnóstico responde [`403 APP_RESPONSIBLE_INACTIVE`](https://os.utilia.ai/docs/developers/getting-started/errors-and-retries#app_responsible_inactive).

### `responsible-inactive`

**La persona responsable ya no está activa** · `RESPONSIBLE_INACTIVE` · Bloquea · Lo arregla la organización

Está dada de baja o bloqueada, y todas las llamadas se rechazan con `APP_RESPONSIBLE_INACTIVE`. Pide a un administrador que nombre otra. Solo se ve en la pestaña **Pruebas** del panel y por MCP, por el mismo motivo que [`responsible-missing`](#responsible-missing).

### `key-previous-in-use`

**Se está usando la clave anterior** · `KEY_PREVIOUS_IN_USE` · Aviso, o bloquea si la anterior ya no vale · Lo arreglas tú

La clave se renovó y tu integración sigue llamando con la anterior, que dejará de valer al terminar la transición. Cámbiala por la nueva en tu configuración antes de esa fecha (`previousKeyExpiresAt`).

La variante que bloquea se titula **La integración sigue con la clave anterior, que ya no vale**: la transición terminó (o la renovación fue sin transición) y las últimas llamadas de tu integración se hicieron con la clave anterior, sin ninguna con la nueva, así que se rechazan con `API_KEY_INVALID`. Durante los primeros 15 minutos después de que dejara de valer es un aviso; después, bloquea y la salud pasa a **No funciona**. Cambia la clave por la nueva; si no la tienes, pide a un administrador que te la pase o que la vuelva a renovar.

### `key-in-url`

**La clave viaja en la dirección** · `KEY_IN_URL` · Aviso · Lo arreglas tú

En los últimos 30 días han llegado llamadas con la clave en la dirección (en `apiKey`, `api_key`, `x-api-key` u otro parámetro), donde queda en registros, servidores intermedios e historial. Sola en la dirección, la llamada se rechaza con [`401 API_KEY_IN_URL_NOT_ALLOWED`](https://os.utilia.ai/docs/developers/getting-started/errors-and-retries#api_key_in_url_not_allowed); si la petición trae además la cabecera `X-Api-Key`, de momento entra por la cabecera. En los dos casos queda constancia y sale este hallazgo.

Quítala de la dirección cuanto antes, porque esa tolerancia dejará de existir, y pide que se renueve la clave: la que viajó en la dirección puede estar expuesta. Para las conexiones en tiempo real, pide antes un pase de conexión.

### `credential-advisory-open`

**Hay una recomendación de renovar la clave** · `CREDENTIAL_ADVISORY_OPEN` · Aviso · Lo arregla la organización

Hay una recomendación de seguridad abierta sobre las credenciales de la aplicación. Pide a un administrador que la revise y, si procede, renueve la clave. No sale con una clave publicada en una web.

### `origins-unrestricted`

**Cualquier web puede usar la clave** · `ORIGINS_UNRESTRICTED` · Aviso · Lo arregla la organización

La aplicación llama desde el navegador y no tiene dominios autorizados: la clave queda a la vista en la página y cualquier web podría usarla. Pide a un administrador que limite los dominios autorizados a los de tu web. La clave ya se trata como [publicada en una web](https://os.utilia.ai/docs/developers/getting-started/diagnostics#claves-publicadas-en-una-web), porque se ha usado desde un navegador. No sale con la clave publicada: lo ve la organización en la pestaña **Pruebas** del panel.

### `publishable-key-sensitive-scopes`

**La clave publicada en páginas web tiene permisos de servidor** · `PUBLISHABLE_KEY_SENSITIVE_SCOPES` · Aviso · Lo arregla la organización

La clave está publicada en páginas web (tiene dominios autorizados o se ha usado desde un navegador) y además tiene permisos que una clave así no debe usar: solo admite los del widget (tickets, sugerencias de IA de los tickets, archivos, `users.identify` y el envío de errores). Desde el navegador, esas rutas responden [`403 SCOPE_NOT_ALLOWED_FROM_BROWSER`](https://os.utilia.ai/docs/developers/getting-started/errors-and-retries#scope_not_allowed_from_browser), y con una clave publicada no cuentes con ellas tampoco desde tu servidor: también ahí pueden responder `403`. Es un aviso: no lleva la salud a **No funciona** ni manda correos.

Pide a un administrador que separe la integración en dos aplicaciones: esta, con los dominios y solo los permisos de la web, y otra sin dominios autorizados, con su propia clave, para tu servidor. Si tu web ya no llama a la API desde el navegador, la otra salida es quitar los dominios **y** renovar la clave: quitar los dominios no basta, porque la clave estuvo en una página. Ver [Claves dentro de una página web](https://os.utilia.ai/docs/developers/getting-started/rate-limits-and-cors#claves-dentro-de-una-página-web). No sale con la clave publicada: lo ve la organización en la pestaña **Pruebas** del panel.

### `publishable-key-ceiling-unavailable`

**La protección de las claves publicadas no se está aplicando** · `PUBLISHABLE_KEY_CEILING_UNAVAILABLE` · Aviso · Lo arreglamos nosotros

UTILIA OS no está aplicando ahora mismo el límite de permisos de las claves publicadas en páginas web. Cada ruta sigue comprobando sus permisos. No hace falta cambiar nada en tu integración; mientras tanto, revisa que la aplicación solo tenga los permisos que usa su web y, si sigue, abre un ticket a UTILIA. Solo sale en la pestaña **Pruebas** del panel y por MCP, y solo con una clave publicada.

### `widget-identity-not-verified`

**El widget no verifica a quién atiende** · `WIDGET_IDENTITY_NOT_VERIFIED` · Aviso · Lo arregla la organización

La clave de la aplicación está publicada en páginas web, tiene permisos de tickets y el widget identifica a cada persona solo por el `userId` que manda el navegador: quien copie la clave puede leer y escribir los tickets de otra persona cambiando ese valor. Pide a un administrador que genere el secreto del widget en la ficha de la aplicación; cuando tu servidor firme el `userId` con él y se lo pase al widget en `userSignature`, que active la verificación obligatoria. Mientras se prueba, el modo que solo registra los fallos no bloquea nada. Lo explica [Verificar la identidad en el widget](https://os.utilia.ai/docs/developers/widget/identity-verification). No sale con la clave publicada: lo ve la organización en la pestaña **Pruebas** del panel.

### `widget-identity-secret-missing`

**El widget exige la firma y falta su secreto** · `WIDGET_IDENTITY_SECRET_MISSING` · Aviso, o bloquea si se están rechazando peticiones · Lo arregla la organización

La aplicación exige verificar a las personas del widget, pero no tiene secreto del widget: toda petición del widget que lleva un `userId` se rechaza con [`403 WIDGET_IDENTITY_SECRET_MISSING`](https://os.utilia.ai/docs/developers/getting-started/errors-and-retries#widget_identity_secret_missing). Es un aviso mientras no haya rechazos; pasa a bloqueo cuando se están rechazando peticiones del widget. Pide a un administrador que genere el secreto del widget en la ficha de la aplicación y te lo pase para firmar el `userId` en tu servidor.

## Permisos y plan

### `no-scopes`

**La aplicación no tiene permisos de la API** · `NO_SCOPES` · Bloquea · Lo arregla la organización

Solo puede consultar su propio diagnóstico, y el resto se rechaza con `INSUFFICIENT_SCOPE`. Pide a un administrador que conceda los que necesitas.

### `scope-module-not-in-plan`

**Un permiso de la aplicación no está incluido en el plan** · `SCOPE_MODULE_NOT_IN_PLAN` · Bloquea · Lo arregla la organización

La aplicación tiene un permiso de un aplicativo que el plan de la organización no incluye: esas llamadas se rechazan con `MODULE_NOT_ENABLED`. `moduleKey` dice cuál. Pide a un administrador que revise el plan, o deja de llamar a esas rutas.

### `scope-capability-not-active`

**Un permiso necesita una función que el plan no tiene activa** · `SCOPE_CAPABILITY_NOT_ACTIVE` · Bloquea · Lo arregla la organización

Esas llamadas se rechazan con `CAPABILITY_NOT_ENABLED`. Pide a un administrador que revise el plan, o deja de llamar a esas rutas.

### `scope-coming-soon`

**Un permiso corresponde a una función en «Próximamente»** · `SCOPE_COMING_SOON` · Información · Lo arreglamos nosotros

Hasta que esté disponible, esas llamadas se rechazan con `FEATURE_COMING_SOON`. No hace falta hacer nada: el permiso funcionará sin cambios cuando llegue.

### `scope-grace-ending`

**Un permiso pasará a ser obligatorio** · `SCOPE_GRACE_ENDING` · Aviso · Lo arregla la organización

Algunas llamadas funcionan hoy sin su permiso porque está en transición; cuando termine, se rechazarán con `INSUFFICIENT_SCOPE`. La cabecera `X-Deprecation-Warning` dice cuál y desde cuándo. Pide a un administrador que lo conceda antes.

### `scope-missing-for-observed-calls`

**Llamadas rechazadas por falta de permiso** · `SCOPE_MISSING_FOR_OBSERVED_CALLS` · Aviso · Lo arregla la organización

En la última hora, tu aplicación ha llamado a rutas que exigen un permiso que no tiene, y esas llamadas se han rechazado con `INSUFFICIENT_SCOPE`. El hallazgo trae la ruta, cuántas llamadas y, si se deduce de la ruta, el permiso. Pide a un administrador que lo conceda solo si tu integración necesita esa ruta; si no la necesita, deja de llamarla.

Es un aviso y no un bloqueo: cualquiera que tenga la clave puede provocar estos rechazos, y una aplicación no está rota por no tener un permiso que nunca tuvo. No lleva la salud a **No funciona** ni manda correos. Los rechazos de hace más de una hora pasan a contarse en [`rejected-calls`](#rejected-calls), como información. Tiene dos variantes:

- **El permiso depende de lo que pides** (un subpermiso, o uno que depende de los datos de la petición): el hallazgo no puede nombrarlo, y lo dice `requiredScopes` en la respuesta de esas llamadas.
- **Clave publicada en una web**: la clave está a la vista y las llamadas pueden no venir de tu web, así que no se propone conceder nada. Si tu web no usa esas rutas, los rechazos son la protección funcionando y no hay que hacer nada.

En la pestaña **Pruebas** del panel, la acción es **Revisar el permiso**, que lleva a los permisos de la aplicación sin concederlo de un toque; con una clave publicada en una web, solo **Ver qué significa**.

### `telemetry-scope-missing`

**Los errores del SDK no se están registrando** · `TELEMETRY_SCOPE_MISSING` · Aviso · Lo arregla la organización

El SDK intenta enviar los errores de tu aplicación y le falta el permiso para registrarlos, así que se pierden. Todo lo demás funciona. Pide a un administrador el permiso para reportar errores.

## Facturación

### `billing-disabled-with-invoice-scopes`

**La facturación de la aplicación está desactivada** · `BILLING_DISABLED_WITH_INVOICE_SCOPES` · Bloquea · Lo arregla la organización

La aplicación tiene permisos de facturas, pero la facturación está desactivada y cada emisión se rechaza con `BILLING_NOT_ENABLED`. Pide a un administrador que la active; mientras tanto, prueba con `POST /external/v1/invoices/validate`, que no emite nada.

### `finance-not-in-plan-with-invoice-scopes`

**Finanzas no está incluida en el plan** · `FINANCE_NOT_IN_PLAN_WITH_INVOICE_SCOPES` · Bloquea · Lo arregla la organización

La aplicación tiene permisos de facturas o cobros, pero el plan no incluye Finanzas: esas llamadas se rechazan con `MODULE_NOT_ENABLED`. Pide a un administrador que revise el plan.

### `invoice-send-scope-missing`

**Falta el permiso para enviar facturas por correo** · `INVOICE_SEND_SCOPE_MISSING` · Aviso · Lo arregla la organización

La aplicación envía sus facturas por correo sin el permiso de envío. Hoy se tolera con un aviso; cuando sea obligatorio, el correo dejará de salir. Pide a un administrador el permiso «Enviar facturas por correo» (`crm:invoices:send`).

### `organization-fiscal-data-incomplete`

**Faltan datos fiscales de la organización** · `ORGANIZATION_FISCAL_DATA_INCOMPLETE` · Bloquea · Lo arregla la organización

Para emitir facturas hacen falta el nombre o la razón social, el NIF, la dirección, la ciudad y el código postal de la organización, que es quien las emite. Si falta alguno, cada factura que tu aplicación intente emitir se rechazará, también con la facturación activada. El `detail` dice cuáles faltan («Faltan: NIF y ciudad.»).

Pide a un administrador de tu organización que los complete en **Ajustes › Organización**: la razón social y el NIF, en la pestaña «General»; el domicilio, en «Direcciones». Mientras tanto, `POST /external/v1/invoices/validate` dice qué falta sin emitir nada.

Solo sale si la aplicación tiene permisos de facturas y el plan incluye Finanzas. Como ninguna llamada lo confirma por sí sola, el veredicto es «Falta un paso»: no lleva la salud a **No funciona** ni manda correos.

## Avisos a tu servidor

### `webhooks-incomplete`

**La configuración de los avisos está incompleta** · `WEBHOOKS_INCOMPLETE` · Aviso · Lo arregla la organización

Los avisos están activados, pero falta la dirección, la clave de firma o algún evento suscrito, así que no se envía nada. Pide a un administrador que complete la configuración de los avisos.

### `webhook-events-out-of-plan`

**Hay eventos suscritos que el plan no incluye** · `WEBHOOK_EVENTS_OUT_OF_PLAN` · Aviso · Lo arregla la organización

Hay eventos suscritos de un aplicativo que el plan no incluye; esos avisos no se envían. Pide a un administrador que revise los eventos o el plan.

### `webhook-deliveries-failing`

**Los avisos no llegan al servidor de la aplicación** · `WEBHOOK_DELIVERIES_FAILING` · Bloquea, o aviso si ya se han recuperado · Lo arreglas tú

Varias entregas han fallado sin remedio en las últimas 24 horas. Comprueba que tu servidor está accesible y contesta `2xx` a tiempo; el historial de entregas de la aplicación dice qué contestó. Ver [Entregas y reintentos](https://os.utilia.ai/docs/developers/webhooks/delivery-and-retries).

### `webhook-receiver-accepts-invalid-signature`

**El servidor de la aplicación acepta avisos sin firma válida** · `WEBHOOK_RECEIVER_ACCEPTS_INVALID_SIGNATURE` · Aviso · Lo arreglas tú

En la última [comprobación del receptor](https://os.utilia.ai/docs/developers/getting-started/webhook-testing#comprobar-tu-receptor-de-avisos), tu servidor aceptó un aviso con la firma falsa o la marca de tiempo caducada. Verifica la firma y la marca de tiempo de cada aviso y contesta `4xx` si no cuadran. Ver [Firma HMAC de los avisos](https://os.utilia.ai/docs/developers/webhooks/hmac-signature). No sale con una clave publicada en una web: míralo en el panel.

### `webhook-secret-transition-ending`

**La clave de firma anterior deja de valer pronto** · `WEBHOOK_SECRET_TRANSITION_ENDING` · Aviso · Lo arreglas tú

Durante una renovación los avisos se firman con las dos claves; cuando termine, solo con la nueva. Configura la clave de firma nueva en tu servidor antes de esa fecha.

## Tráfico observado

### `rejected-calls`

**Hay llamadas rechazadas** · `REJECTED_CALLS` · Aviso, bloquea o información · Lo arregla quien diga el código de cada grupo

Algunas llamadas reciben un error. Hay un hallazgo por cada grupo de llamadas rechazadas (una ruta, un método y un código), hasta cinco, y su título lo dice: «12 llamadas rechazadas en POST /external/v1/tickets (VALIDATION_ERROR)», o «1 llamada rechazada en…» si es una. `fixedBy` es el del código del grupo. Consulta [las llamadas rechazadas](https://os.utilia.ai/docs/developers/getting-started/diagnostics#llamadas-rechazadas): cada grupo dice qué falla y quién lo arregla.

- **Bloquea** cuando el fallo es reciente y la ruta falla casi siempre (el 90 % de 5 llamadas o más en 24 horas), o cuando en la última hora se rechaza al menos la mitad de 20 llamadas o más.
- **Aviso** cuando el grupo pesa: al menos 5 llamadas y el 5 % de las de su ruta en 24 horas, o cualquier rechazo que arregla la organización. Ver [Qué tráfico cuenta](https://os.utilia.ai/docs/developers/getting-started/app-health#qué-tráfico-cuenta).
- **Información** por debajo de ese umbral, en un `404` al leer por identificador y en los rechazos por falta de permiso de hace más de una hora.

Un rechazo por falta de permiso, de origen o del permiso de la persona responsable nunca bloquea. Los grupos cuya causa ya se arregló (`resolved: true`) no generan hallazgo. Si otros hallazgos ya explican parte de los rechazos, este cuenta solo los demás, con el mismo título por ruta.

### `rate-limit-hits`

**Se ha superado el límite de llamadas** · `RATE_LIMIT_HITS` · Aviso o información · Lo arreglas tú

Algunas llamadas se rechazaron con `429` por superar el límite. Espera lo que indica `Retry-After` antes de reintentar y reparte las llamadas en el tiempo. Es un aviso con al menos 5 rechazos y el 5 % de las llamadas de 24 horas; por debajo, información: un `429` suelto lo reintenta el SDK solo.

### `server-errors`

**Algunas llamadas fallaron por un error nuestro** · `SERVER_ERRORS` · Aviso o información · Lo arreglamos nosotros

Algunas llamadas fallaron por un error interno de UTILIA OS, no por tu integración. Ya nos ha llegado; si se repite, escríbenos con el `requestId` de la llamada. Es un aviso con al menos 5 errores y el 5 % de las llamadas de 24 horas; por debajo, información.

### `reported-errors-open`

**Hay errores de la aplicación sin resolver** · `REPORTED_ERRORS_OPEN` · Información o aviso · Lo arreglas tú

Tu aplicación ha reportado errores que siguen abiertos. Revísalos con `GET /external/v1/errors`. Pasa a aviso si alguno es crítico.

### `sdk-outdated`

**El SDK está desactualizado** · `SDK_OUTDATED` · Aviso · Lo arreglas tú

La versión del SDK que usa tu aplicación está por debajo de la mínima recomendada. Actualízalo; ver [Versiones y compatibilidad](https://os.utilia.ai/docs/developers/sdk/versions).

### `no-traffic`

**La aplicación no ha usado la API en los últimos 30 días** · `NO_TRAFFIC` · Información · Lo arreglas tú

No hay llamadas a la API en los últimos 30 días. Las de `GET /external/v1/me` y las del propio diagnóstico no cuentan como uso. Haz una primera llamada con tu clave en `X-Api-Key`; la [guía de inicio rápido](https://os.utilia.ai/docs/developers/getting-started/quickstart) tiene un ejemplo.

Si la clave ya ha respondido bien a `/me` o al diagnóstico, el hallazgo se titula **La clave funciona, pero la aplicación aún no usa la API**: la clave y la red funcionan y no hace falta repetir esa prueba. Haz tu primera llamada a una ruta que la aplicación ya pueda usar; `access`, en el diagnóstico, las enumera con el permiso que pide cada una.

## Primeros pasos que se marcan solos

`journey`, en el diagnóstico, lista los primeros pasos según para qué sirve tu aplicación (`purposes`) y los marca con lo que observa el servidor: una llamada registrada con tu clave, un aviso entregado, la configuración. No hay casillas que marcar a mano. Cada paso trae `docsUrl` con su ancla aquí y `runnableFromPanel`, que dice si la pestaña **Pruebas** del panel puede marcarlo.

Solo uno puede: el del receptor de avisos, porque la comprobación guarda su resultado lo lance quien lo lance. Por eso **Probar aquí**, en el panel, solo aparece en ese paso. La factura de prueba y la prueba activa del panel se ejecutan sin tu clave y no dejan llamadas registradas, así que no marcan ninguno: los demás se marcan cuando tu programa los hace.

### `recorrido-first-call-ok`

**Primera llamada correcta** (`first_call_ok`). Cualquier respuesta correcta con la clave en `X-Api-Key`, también `GET /external/v1/me` o el propio diagnóstico: prueba que la clave y la red funcionan. La llamada que estás haciendo también cuenta, así que tu primer `GET /external/v1/diagnostics` ya trae este paso hecho. Una llamada que tu programa corta antes de la respuesta (`499`) no cuenta.

Este paso no es lo mismo que usar la API: para el veredicto y el hallazgo [`no-traffic`](#no-traffic), las llamadas a `/me` y al diagnóstico no cuentan como uso. Con la clave probada y sin más llamadas, el veredicto es «Todavía no usa la API».

### `recorrido-invoice-validated`

**Factura validada sin emitirla** (`invoice_validated`). `POST /external/v1/invoices/validate` con la clave y el cuerpo de tu factura: lo comprueba todo y no emite nada. Solo lo marca una validación que responde `valid: true`; la que encuentra bloqueos responde `200` igual, pero no cuenta. La factura de prueba del panel tampoco marca este paso. Ver [Validar una factura sin emitirla](https://os.utilia.ai/docs/developers/api/invoice-testing#validar-una-factura-sin-emitirla).

### `recorrido-invoice-pdf-sample`

**PDF de muestra generado** (`invoice_pdf_sample`). `POST /external/v1/invoices/validate/pdf`, con la clave, devuelve cómo quedará la factura, con el número «PRUEBA». El PDF de muestra del panel no marca este paso. Ver [PDF de prueba](https://os.utilia.ai/docs/developers/api/invoice-testing#pdf-de-prueba).

### `recorrido-billing-enabled`

**Facturación activada** (`billing_enabled`). La activa un Super Administrador en **Dinero › Facturación** de la ficha de la aplicación, con un motivo. Ver [la guía de facturación](https://os.utilia.ai/docs/developers/api/billing-guide#paso-1-activar-la-facturación-de-la-aplicación).

### `recorrido-first-invoice-issued`

**Primera factura emitida** (`first_invoice_issued`). `POST /external/v1/invoices`, con una clave de idempotencia que salga de tu pedido. Es el primer documento con número.

### `recorrido-payment-marked`

**Primer cobro registrado** (`payment_marked`). `POST /external/v1/invoices/:id/mark-paid` marca como cobrada una factura cobrada fuera de la pasarela. Ver [Registrar un cobro fuera de la pasarela](https://os.utilia.ai/docs/developers/api/invoice-actions#registrar-un-cobro-fuera-de-la-pasarela).

### `recorrido-first-ticket`

**Primer ticket creado** (`first_ticket`). `POST /external/v1/tickets` crea el primer ticket de soporte. Ver [Tickets](https://os.utilia.ai/docs/developers/api/tickets).

### `recorrido-first-crm-read`

**Primera lectura del CRM** (`first_crm_read`). Una consulta correcta de clientes, contactos o leads hecha con la clave, como `GET /external/v1/clients`. La prueba activa no lo marca: sus lecturas no cuentan como llamadas de tu aplicación.

### `recorrido-first-lead-created`

**Primer lead creado** (`first_lead_created`). Solo si la aplicación tiene `crm:leads:write`: `POST /external/v1/leads` crea el primero. Ver [Leads](https://os.utilia.ai/docs/developers/api/leads).

### `recorrido-receiver-checked`

**Receptor de avisos comprobado** (`receiver_checked`). La [comprobación del receptor](https://os.utilia.ai/docs/developers/getting-started/webhook-testing#comprobar-tu-receptor-de-avisos) tiene que ver que tu servidor acepta el aviso bueno y rechaza los dos falsos. Es el único paso que se marca desde el panel: **Probar aquí** lanza esa misma comprobación.

### `recorrido-first-delivery-ok`

**Primer aviso entregado** (`first_delivery_ok`). Llega cuando ocurre un evento al que la aplicación está suscrita y tu servidor contesta con un `2xx`.

## Siguiente paso

- [Errores y reintentos](https://os.utilia.ai/docs/developers/getting-started/errors-and-retries): Qué significa cada errorCode, quién lo arregla y cuándo repetir.
- [La pestaña Pruebas](https://os.utilia.ai/docs/developers/api/apps-panel#la-pestaña-pruebas): Los mismos hallazgos en el panel, con la acción de cada uno.
