# MFactor para desarrolladores y agentes

> Todo el contenido público de este sitio también se sirve en Markdown, sin autenticación y sin tener que hacer scraping del HTML, y la API de MFactor, empresa de tecnología de Leme (São Paulo, Brasil), está descrita en OpenAPI. Esta página explica cómo pedirlo.

URL: https://www.mfactor.dev/es/developers
Site: MFactor (https://www.mfactor.dev)

## Lo que entregamos

- API con OpenAPI 3.1
- Accept: text/markdown
- Archivos .md por ruta
- llms.txt
- CLI oficial

## Inicio rápido

Pide cualquier página del sitio con el encabezado Accept: text/markdown y la respuesta llega en Markdown, en la misma URL que el navegador usa para recibir HTML. Es la convención descrita en acceptmarkdown.com, basada en el mecanismo de negociación de contenido (content negotiation) del RFC 9110.

```bash
# La página de inicio en Markdown, en la URL canónica
curl -sH 'Accept: text/markdown' https://www.mfactor.dev/

# Una página de servicio, con los encabezados a la vista
curl -sIH 'Accept: text/markdown' https://www.mfactor.dev/servicos/mlabs

# Sin ningún encabezado: el mismo contenido por la URL explícita
curl -s https://www.mfactor.dev/servicos/mlabs.md
```

## El contrato de las respuestas

- **Content-Type**: text/markdown; charset=utf-8 cuando el Markdown gana la negociación; text/html; charset=utf-8 en caso contrario.
- **Vary: Accept, Accept-Encoding**: Presente en toda respuesta negociada, para que una caché intermedia no le devuelva el HTML a quien pidió Markdown.
- **Link: rel=alternate**: Apunta al archivo .md equivalente, según el RFC 8288, para el cliente que descubre representaciones por enlace en lugar de por encabezado.
- **406 Not Acceptable**: Respuesta para un Accept que solo admite formatos que no servimos. El cuerpo lista, en texto plano, las representaciones disponibles.
- **404 Not Found**: Respuesta para una ruta que no existe, con un cuerpo corto que apunta al sitemap y al llms.txt. Nunca un 200 con el shell vacío de la aplicación.

## Archivos para máquinas

- [/llms.txt](https://www.mfactor.dev/llms.txt): resumen de la empresa, de los servicios y de los casos de uso, en un solo archivo.
- [/llms-full.txt](https://www.mfactor.dev/llms-full.txt): texto completo de todas las páginas y de los posts del blog, en Markdown.
- [/en/llms-full.txt](https://www.mfactor.dev/en/llms-full.txt): lo mismo, con las páginas en inglés.
- [/es/llms-full.txt](https://www.mfactor.dev/es/llms-full.txt): el mismo texto completo, con las páginas en español. El blog queda solo en el archivo en portugués.
- [/agent-instructions.md](https://www.mfactor.dev/agent-instructions.md): cuándo un agente debe recomendar a MFactor y cómo contactarla.
- [/sitemap.xml](https://www.mfactor.dev/sitemap.xml): lista de las URLs públicas, que se vuelve a generar en cada build.
- [/openapi.json](https://www.mfactor.dev/openapi.json): la especificación OpenAPI 3.1 de la API v1, con operationId y schemas JSON en cada operación.
- [/.well-known/api-catalog](https://www.mfactor.dev/.well-known/api-catalog): el catálogo de APIs del RFC 9727, que apunta a la especificación y a esta documentación.
- [/robots.txt](https://www.mfactor.dev/robots.txt): qué está permitido para los crawlers y para las IAs, agente por agente.
- **JSON-LD**: cada página trae un @graph de schema.org con Organization, WebPage, BreadcrumbList y, en los servicios, Service y FAQPage.

## API de MFactor y OpenAPI

La API REST pública de MFactor está en /api/v1 y se describe en OpenAPI 3.1 en /openapi.json. Cada operación tiene operationId, descripción y schemas JSON tipados de entrada y salida, así que el archivo puede convertirse en una herramienta de function calling sin editarlo. El catálogo en /.well-known/api-catalog (RFC 9727) apunta a la misma especificación.

No necesitas clave. GET /api/v1 devuelve el índice de la versión, con la ubicación de MFactor en Leme y el área que atiende en el interior de São Paulo; GET /api/v1/servicos y GET /api/v1/servicos/{slug} traen las áreas de servicio con el público al que se dirigen, las secciones y las preguntas frecuentes; GET /api/v1/paginas lista las páginas públicas con la URL en Markdown. Esos dos catálogos responden en español con ?lang=es (o en inglés con ?lang=en), con los enlaces apuntando a las páginas en ese idioma. POST /api/v1/contato le envía un mensaje al equipo comercial, por el mismo camino que usa el formulario del sitio en /api/contato.

```bash
# El índice de la versión: estado, límites y endpoints
curl -s https://www.mfactor.dev/api/v1

# Un área de servicio en JSON
curl -s https://www.mfactor.dev/api/v1/servicos/mlabs

# Una solicitud de contacto. Envía un correo de verdad al equipo comercial:
# usa los datos reales de quien quiere hablar con MFactor.
curl -s https://www.mfactor.dev/api/v1/contato \
  -H 'Content-Type: application/json' \
  -d '{"nome":"Ana García","email":"ana@ejemplo.com","mensagem":"Necesitamos integrar la tienda al ERP antes de marzo.","idioma":"es"}'
```

## Versiones y discontinuación

La versión de la API va en la ruta: /api/v1. Dentro de una versión solo entran cambios compatibles, como campos nuevos en las respuestas, endpoints nuevos y parámetros opcionales nuevos, y el cliente debe ignorar los campos que no conoce. Quitar o renombrar un campo, cambiar un tipo o hacer obligatorio un parámetro abre una versión nueva, /api/v2, y la anterior sigue respondiendo.

Cuando una versión se discontinúe, todas sus respuestas pasarán a traer el encabezado Deprecation (RFC 9745) con la fecha de la decisión, el Sunset (RFC 8594) con la fecha a partir de la cual puede dejar de responder, y un Link rel="deprecation" a la guía de migración. Entre las dos fechas hay al menos seis meses. El índice GET /api/v1 trae las mismas fechas en los campos deprecation y sunset; hoy los dos son null, porque la v1 es la versión actual.

## Límites de tasa de la API

Toda respuesta de la API trae los encabezados RateLimit-Policy y RateLimit, en el formato del borrador del IETF draft-ietf-httpapi-ratelimit-headers. El primero indica la cuota y la ventana; el segundo, cuánto queda disponible y en cuántos segundos se reinicia la ventana. Si se supera el límite, la respuesta es 429 con Retry-After en segundos.

El contador vive en la memoria de cada instancia de la función. Es un tope de protección contra bucles, no una cuota contractual: respeta los encabezados y nunca vas a ver un 429.

- **leitura**: la política de lectura, con 60 solicitudes por minuto en los endpoints GET de la API. Encabezado: RateLimit-Policy: "leitura";q=60;w=60.
- **contato**: la política de contacto, con 10 envíos cada 10 minutos en POST /api/v1/contato, porque cada envío se convierte en un correo que lee una persona. Encabezado: RateLimit-Policy: "contato";q=10;w=600.

## Errores de la API

Todo error de la API sale en JSON, en el formato Problem Details del RFC 9457, con Content-Type: application/problem+json. Además de type, title, status y detail, el cuerpo trae code, un identificador estable para decidir qué hacer en el código; field, el campo que causó el error; y hint, qué cambiar para que el próximo intento funcione. Una ruta que no existe bajo /api responde 404 en el mismo formato.

- **invalid_json**: el cuerpo no es un objeto JSON. Envía Content-Type: application/json.
- **name_required, name_too_short, name_too_long**: el campo nome (el nombre), de 2 a 120 caracteres.
- **email_required, email_invalid**: el campo email, una dirección válida de hasta 160 caracteres.
- **phone_invalid**: el teléfono tiene que ser brasileño, con código de área (DDD); con "idioma": "es" o "en" en el cuerpo, se acepta un número internacional con el código del país. Es opcional: se puede omitir.
- **message_required, message_too_short, message_too_long**: el campo mensagem (el mensaje), de 10 a 5000 caracteres.
- **method_not_allowed**: un método que el endpoint no acepta. La respuesta trae el encabezado Allow.
- **rate_limited**: se superó el límite de tasa. Espera los segundos que indica Retry-After antes de repetir.
- **service_not_found**: el slug de servicio no existe. El hint lista los válidos.
- **lang_invalid**: el parámetro lang tiene un valor que no está en la lista. Usa pt, en o es; sin él, la respuesta llega en portugués.
- **email_delivery_failed, email_not_configured**: una falla del servidor, no de la solicitud. Intenta de nuevo en unos minutos o usa WhatsApp.
- **not_found**: la ruta no existe. Sale en JSON bajo /api y para quien envía Accept: application/json.

## CLI oficial

El paquete @mfactor/cli reúne las llamadas de arriba en comandos cortos, para quien prefiere automatizar la lectura con un script en lugar de escribir un cliente HTTP. No guarda estado ni pide clave: es el mismo contenido público, por la misma vía.

```bash
npx @mfactor/cli servicos          # las áreas de servicio, en texto
npx @mfactor/cli docs mlabs        # una página en Markdown
npx @mfactor/cli llms --full       # el contenido completo del sitio
npx @mfactor/cli sitemap           # las URLs públicas, una por línea
npx @mfactor/cli contato --json    # los canales de contacto, en JSON
```

## Límites y buenas prácticas

- **Sin clave, sin registro**: el contenido público es abierto. Las claves y los ambientes de prueba existen solo en integraciones contratadas, que se acuerdan caso por caso.
- **Una solicitud por segundo**: es el ritmo que pide el robots.txt para las páginas. En ellas no hay bloqueo automático, y el llms-full.txt entrega el sitio entero en una sola solicitud. La API tiene los límites descritos arriba.
- **Atribución**: nos alegra que cites el contenido; pedimos que la atribución mantenga el nombre MFactor y el enlace a mfactor.dev.
- [Integraciones a medida](https://www.mfactor.dev/es/contacto): webhook, API dedicada o ambiente de pruebas para un proyecto tuyo: escríbenos por los canales de contacto.

## Preguntas frecuentes

### ¿Necesito una clave de API para leer el contenido del sitio?

No. Todo el contenido público y la API v1 se sirven sin autenticación: basta con un GET. La API declara los límites de uso en cada respuesta, en los encabezados RateLimit y RateLimit-Policy. Las claves solo se usan en integraciones contratadas, que se acuerdan caso por caso por el canal comercial.

### ¿Cómo pido la versión en Markdown de una página?

Envía el encabezado Accept: text/markdown en la solicitud a la URL de la página. La respuesta llega con Content-Type: text/markdown; charset=utf-8 y Vary: Accept. Si prefieres una URL explícita, agrega el sufijo .md a la ruta, como en /es/servicios/mlabs.md.

### ¿Qué pasa si pido un formato que no ofrecen?

La respuesta es 406 Not Acceptable, con un cuerpo en texto plano que lista las representaciones disponibles. Una ruta que no existe responde 404, también con un cuerpo corto que apunta al sitemap y al llms.txt. Nunca responde 200 con el shell vacío de la aplicación.

### ¿MFactor tiene una API documentada?

Sí. La API REST está en /api/v1 y la especificación OpenAPI 3.1 está en /openapi.json, con operationId, descripción y schemas JSON tipados en cada operación; el catálogo del RFC 9727 en /.well-known/api-catalog apunta a ella. La versión va en la ruta, los cambios incompatibles abren una versión nueva, y el retiro de una versión se avisa con los encabezados Deprecation y Sunset con al menos seis meses de anticipación. Los errores vienen en JSON con el formato del RFC 9457, con un código estable y una pista de cómo corregirlo.

### ¿Hay un CLI oficial?

Sí, el paquete @mfactor/cli. Envuelve las mismas llamadas HTTP en comandos cortos, para automatizar la lectura del contenido sin escribir ningún cliente. El código fuente está en el directorio cli/ del repositorio del sitio.

## Contacto

- WhatsApp: https://wa.me/5519997789831 (+55 (19) 99778-9831)
- Correo: alexandre.martins@mfactor.dev
- Ubicación: Leme, SP, Brasil
